#include <afxwin.h>
#include "app_utils.h"
#include "service_frame.h"

CWinApp app;

int test_frame()
{   
    WORD wVersionRequested = MAKEWORD(2, 0);
    WSADATA wsaData;
    WSAStartup( wVersionRequested, &wsaData );
    file_logger logger(file_logger::get_app_path()+"/ims.txt");

    logger<<file_logger::begin()
        <<"------------------------------------log beg------------------------------------"
        <<file_logger::end();
    {
        service_frame frame;

        frame.set_trace_mod(&logger);

        frame.initialize();

        system_pause();        
    }
    logger<<file_logger::begin()
        <<"------------------------------------log end------------------------------------"
        <<file_logger::end();
    WSACleanup();

    return 0;
}

/**
 * section: Parsing
 * synopsis: Parse an XML document chunk by chunk to a tree and free it
 * purpose: Demonstrate the use of xmlCreatePushParserCtxt() and
 *          xmlParseChunk() to read an XML file progressively
 *          into a tree and and xmlFreeDoc() to free the resulting tree
 * usage: parse4 test3.xml
 * test: parse4 test3.xml
 * author: Daniel Veillard
 * copy: see Copyright for the status of this software.
 */

#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <stack>

#ifdef LIBXML_PUSH_ENABLED
static FILE *desc;

/**
 * readPacket:
 * @mem: array to store the packet
 * @size: the packet size
 *
 * read at most @size bytes from the document and store it in @mem
 *
 * Returns the number of bytes read
 */
static int
readPacket(char *mem, int size) {
    int res;

    res = (int)fread(mem, 1, size, desc);
    return(res);
}


//internalSubsetSAXFunc internalSubset;
//isStandaloneSAXFunc isStandalone;
//hasInternalSubsetSAXFunc hasInternalSubset;
//hasExternalSubsetSAXFunc hasExternalSubset;
//resolveEntitySAXFunc resolveEntity;
//getEntitySAXFunc getEntity;
//entityDeclSAXFunc entityDecl;
//notationDeclSAXFunc notationDecl;
//attributeDeclSAXFunc attributeDecl;
//elementDeclSAXFunc elementDecl;
//unparsedEntityDeclSAXFunc unparsedEntityDecl;
//setDocumentLocatorSAXFunc setDocumentLocator;
//startDocumentSAXFunc startDocument;
//endDocumentSAXFunc endDocument;
//startElementSAXFunc startElement;
//endElementSAXFunc endElement;
//referenceSAXFunc reference;
//charactersSAXFunc characters;
//ignorableWhitespaceSAXFunc ignorableWhitespace;
//processingInstructionSAXFunc processingInstruction;
//commentSAXFunc comment;
//warningSAXFunc warning;
//errorSAXFunc error;
//fatalErrorSAXFunc fatalError; /* unused error() get all the errors */
//getParameterEntitySAXFunc getParameterEntity;
//cdataBlockSAXFunc cdataBlock;
//externalSubsetSAXFunc externalSubset;
//unsigned int initialized;
///* The following fields are extensions available only on version 2 */
//void *_private;
//startElementNsSAX2Func startElementNs;
//endElementNsSAX2Func endElementNs;
//xmlStructuredErrorFunc serror;
std::string             m_xmlstring;
std::stack<size_t>      m_elements_index;


void sax_startDocument(void *user_data)
{

}

void sax_endDocument(void *user_data)
{

}

void sax_charactersSAXFunc(void *ctx,const xmlChar *ch,int len)
{
    for (int i=0; i<len; ++i)
    {
        if (ch[i]!=0x0d && ch[i]!=0x0a && ch[i]!=' ')
        {
            m_xmlstring.push_back(ch[i]);
        }
    }
}

void sax_startElement(void* user_data,const xmlChar* name,const xmlChar ** attrs)
{
    m_elements_index.push(m_xmlstring.length());

    m_xmlstring += "<";
    m_xmlstring += (char*)name;

    if (attrs)
    {
        int i=0;
        while (true)
        {
            const xmlChar *name = attrs[i++];
            if (name==0)
            {
                break;
            }
            const xmlChar *val = attrs[i++];
            if (val==0)
            {
                break;
            }
            m_xmlstring+=" ";
            m_xmlstring+=(char*)name;
            m_xmlstring+="='";
            m_xmlstring+=(char*)val;
            m_xmlstring+="'";
        }
    }    
    m_xmlstring+=">";
}
void sax_handle_element(const char *elstr)
{

}

void sax_endElement(void* user_data,const xmlChar *	name)
{
    m_xmlstring+="</";
    m_xmlstring+=(char*)name;
    m_xmlstring+=">";

    sax_handle_element(&m_xmlstring[m_elements_index.top()]);
    m_elements_index.pop();
}




xmlSAXHandler saxhandle;

/**
 * example4Func:
 * @filename: a filename or an URL
 *
 * Parse the resource and free the resulting tree
 */
static void
example4Func(const char *filename) {
    saxhandle.startDocument = sax_startDocument;
    saxhandle.endDocument = sax_endDocument;
    saxhandle.characters = sax_charactersSAXFunc;
    saxhandle.startElement = sax_startElement;
    saxhandle.endElement = sax_endElement;


    xmlParserCtxtPtr ctxt;
    char chars[4];
    xmlDocPtr doc; /* the resulting document tree */
    int res;

    /*
     * Read a few first byte to check the input used for the
     * encoding detection at the parser level.
     */
    res = readPacket(chars, 4);
    if (res <= 0) {
        fprintf(stderr, "Failed to parse %s\n", filename);
	return;
    }

    /*
     * Create a progressive parsing context, the 2 first arguments
     * are not used since we want to build a tree and not use a SAX
     * parsing interface. We also pass the first bytes of the document
     * to allow encoding detection when creating the parser but this
     * is optional.
     */    

    ctxt = xmlCreatePushParserCtxt(&saxhandle, (void*)filename,
                                   chars, res, filename);
    if (ctxt == NULL) {
        fprintf(stderr, "Failed to create parser context !\n");
	return;
    }

    /*
     * loop on the input getting the document data, of course 4 bytes
     * at a time is not realistic but allows to verify testing on small
     * documents.
     */
    while ((res = readPacket(chars, 4)) > 0) {
        xmlParseChunk(ctxt, chars, res, 0);
    }

    /*
     * there is no more input, indicate the parsing is finished.
     */
    xmlParseChunk(ctxt, chars, 0, 1);

    /*
     * collect the document back and if it was wellformed
     * and destroy the parser context.
     */
    doc = ctxt->myDoc;
    res = ctxt->wellFormed;
    xmlFreeParserCtxt(ctxt);

    if (!res) {
        fprintf(stderr, "Failed to parse %s\n", filename);
    }

    /*
     * since we don't use the document, destroy it now.
     */
    xmlFreeDoc(doc);
}


int libxml2_test(const char *filename) {
    /*
     * this initialize the library and check potential ABI mismatches
     * between the version it was compiled for and the actual shared
     * library used.
     */
    LIBXML_TEST_VERSION

    /*
     * simulate a progressive parsing using the input file.
     */
    desc = fopen(filename, "rb");
    if (desc != NULL) {
	example4Func(filename);
	fclose(desc);
    } else {
        fprintf(stderr, "Failed to parse %s\n", filename);
    }

    /*
     * Cleanup function for the XML library.
     */
    xmlCleanupParser();
    /*
     * this is to debug memory for regression tests
     */
    xmlMemoryDump();
    return(0);
}
#else /* ! LIBXML_PUSH_ENABLED */
int main(int argc, char **argv) {
    fprintf(stderr, "Library not compiled with push parser support\n");
    return(1);
}
#endif



int main(int argc, char *argv[])
{
    libxml2_test((file_logger::get_app_path()+"/testxml.txt").c_str());
    system_pause();
}
